{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Pedestrian example of subscribing to a DataSet\n", "\n", "It is possible to *subscribe* to a dataset. Subscribing means adding a function to the dataset and having the dataset call that function every time a result is added to the dataset (or more rarely, see below).\n", "\n", "### Call signature\n", "\n", "The subscribing function must have the following call signature:\n", "```\n", "fun(results: List[Tuple[Value]], length: int,\n", " state: Union[MutableSequence, MutableMapping]) -> None:\n", " \"\"\"\n", " Args:\n", " results: A list of tuples where each tuple holds the results inserted into the dataset.\n", " For two scalar parameters, X and Y, results might look like [(x1, y1), (x2, y2), ...]\n", " length: The current length of the dataset.\n", " state: Any mutable sequence/mapping that can be used to hold information from call to call.\n", " In practice a list or a dict.\n", " \"\"\"\n", "```\n", "Below we provide an example function that counts the number of times a voltage has exceeded a certain limit.\n", "\n", "### Frequency\n", "\n", "Since calling the function **every** time an insertion is made may be too frequent, a `min_wait` and a `min_count` argument may be provided when subscribing. The dataset will then only call the function upon inserting a result\n", "if `min_wait` seconds have elapsed since the last call (or the start of the subscription, in the time before the first call) and `min_count` results have been added to the dataset since the last call (or the start of the subscription). All the results added in the meantime are queued and passed to the function in one go.\n", "\n", "### Order\n", "\n", "The subscription must be set up **after** all parameters have been added to the dataset." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "from pathlib import Path\n", "from time import sleep\n", "\n", "import numpy as np\n", "\n", "from qcodes.dataset import (\n", " ParamSpec,\n", " initialise_or_create_database_at,\n", " load_or_create_experiment,\n", " new_data_set,\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Example 1: A notification\n", "\n", "We imagine scanning a frequency and reading out a noisy voltage. When the voltage has exceeded a threshold 5 times, we want to receive a warning. Let us initialise our database and create an experiment." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "initialise_or_create_database_at(Path.cwd() / \"subscription_tutorial.db\")\n", "exp = load_or_create_experiment(experiment_name=\"subscription_tutorial\", sample_name=\"no_sample\")" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "dataSet = new_data_set(\"test\",\n", " exp_id=exp.exp_id,\n", " specs=[ParamSpec(\"x\", \"numeric\", unit='Hz'),\n", " ParamSpec(\"y\", \"numeric\", unit='V')])\n", "dataSet.mark_started()" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "def threshold_notifier(results, length, state):\n", " if len(state) > 4:\n", " print(f'At step {length}: The voltage exceeded the limit 5 times! ')\n", " state.clear()\n", " for result in results:\n", " if result[1] > 0.8:\n", " state.append(result[1])" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "# now perform the subscription\n", "# since this is important safety info, we want our callback function called\n", "# on EVERY insertion\n", "sub_id = dataSet.subscribe(threshold_notifier, min_wait=0, min_count=1, state=[])" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "scrolled": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "At step 6: The voltage exceeded the limit 5 times! \n", "At step 11: The voltage exceeded the limit 5 times! \n", "At step 16: The voltage exceeded the limit 5 times! \n", "At step 21: The voltage exceeded the limit 5 times! \n", "At step 26: The voltage exceeded the limit 5 times! \n", "At step 31: The voltage exceeded the limit 5 times! \n", "At step 36: The voltage exceeded the limit 5 times! \n", "At step 41: The voltage exceeded the limit 5 times! \n", "At step 46: The voltage exceeded the limit 5 times! \n", "At step 51: The voltage exceeded the limit 5 times! \n", "At step 56: The voltage exceeded the limit 5 times! \n", "At step 61: The voltage exceeded the limit 5 times! \n", "At step 66: The voltage exceeded the limit 5 times! \n", "At step 71: The voltage exceeded the limit 5 times! \n", "At step 76: The voltage exceeded the limit 5 times! \n", "At step 81: The voltage exceeded the limit 5 times! \n", "At step 86: The voltage exceeded the limit 5 times! \n", "At step 91: The voltage exceeded the limit 5 times! \n", "At step 96: The voltage exceeded the limit 5 times! \n", "At step 101: The voltage exceeded the limit 5 times! \n", "At step 106: The voltage exceeded the limit 5 times! \n", "At step 111: The voltage exceeded the limit 5 times! \n", "At step 116: The voltage exceeded the limit 5 times! \n", "At step 121: The voltage exceeded the limit 5 times! \n", "At step 126: The voltage exceeded the limit 5 times! \n", "At step 131: The voltage exceeded the limit 5 times! \n", "At step 136: The voltage exceeded the limit 5 times! \n", "At step 141: The voltage exceeded the limit 5 times! \n", "At step 146: The voltage exceeded the limit 5 times! \n" ] } ], "source": [ "for x in np.linspace(100, 200, 150):\n", " y = np.random.randn()\n", " dataSet.add_results([{\"x\": x, \"y\": y}])" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "dataSet.unsubscribe_all()" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "## Example 2: ASCII Plotter\n", "\n", "While this example does not represent a data acqusition that one may deal with in a real experiment, it is a fun practice of subscribing to a dataset." ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "dataSet = new_data_set(\"test\", exp_id=exp.exp_id,\n", " specs=[ParamSpec(\"blip\", \"numeric\", unit='bit'),\n", " ParamSpec(\"blop\", \"numeric\", unit='bit')])\n", "dataSet.mark_started()" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "def ASCII_plotter_5bit(results, length, state):\n", " \"\"\"\n", " Glorious 5-bit signal plotter\n", "\n", " Digitises the range (-1, 1) with 4 bits and plots it\n", " in stdout. Crashes and burns if given data outside that\n", " interval.\n", " \"\"\"\n", " for result in results:\n", " plotline = ['.'] * 32\n", " yvalue = result[1]\n", " yvalue += 1\n", " yvalue /= 2\n", " yvalue = int(yvalue*31)\n", " plotline[yvalue] = 'O'\n", " print(''.join(plotline))\n" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [], "source": [ "sub_id = dataSet.subscribe(ASCII_plotter_5bit, min_wait=0, min_count=3, state=[])" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "................O...............\n", "...............O................\n", "..................O.............\n", "..................O.............\n", "....................O...........\n", ".....................O..........\n", "......................O.........\n", "..........................O.....\n", ".........................O......\n", "........................O.......\n", "..........................O.....\n", "...........................O....\n", "............................O...\n", "............................O...\n", ".............................O..\n", "............................O...\n", ".............................O..\n", ".............................O..\n", ".............................O..\n", "..............................O.\n", ".............................O..\n", "...........................O....\n", "...........................O....\n", ".........................O......\n", "........................O.......\n", "........................O.......\n", ".........................O......\n", ".......................O........\n", ".....................O..........\n", ".....................O..........\n", "...................O............\n", "..................O.............\n", "................O...............\n", "...............O................\n", ".............O..................\n", ".............O..................\n", "...........O....................\n", "..........O.....................\n", "........O.......................\n", "........O.......................\n", "......O.........................\n", "......O.........................\n", "....O...........................\n", "...O............................\n", "..O.............................\n", "...O............................\n", "...O............................\n", "..O.............................\n", "O...............................\n", "..O.............................\n", ".O..............................\n", "..O.............................\n", ".O..............................\n", "...O............................\n", "..O.............................\n", "....O...........................\n", "....O...........................\n", ".....O..........................\n", "....O...........................\n", "......O.........................\n", ".......O........................\n", "........O.......................\n", ".........O......................\n", "............O...................\n", ".............O..................\n", "..............O.................\n", "...............O................\n", "...............O................\n", "...................O............\n", "...................O............\n", "...................O............\n", ".....................O..........\n", ".......................O........\n", "......................O.........\n", ".......................O........\n", ".........................O......\n", "..........................O.....\n", ".............................O..\n", "............................O...\n", "............................O...\n", "............................O...\n", ".............................O..\n", ".............................O..\n", ".............................O..\n", "............................O...\n", "............................O...\n", "............................O...\n", "...........................O....\n", "...........................O....\n", "...........................O....\n", "...........................O....\n", ".........................O......\n", "........................O.......\n", "......................O.........\n", "....................O...........\n", "....................O...........\n", "...................O............\n", "................O...............\n", "................O...............\n" ] } ], "source": [ "for x in np.linspace(0, 3*np.pi, 100):\n", " yvalue = 0.9*np.sin(x) + np.random.randn()*0.05\n", " dataSet.add_results([{\"blip\": x, \"blop\": yvalue}])\n", " sleep(0.1)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.4" } }, "nbformat": 4, "nbformat_minor": 2 }